#include "glare.d3d11.ShaderInputDeclaration.h"
#include "glare.d3d11.Driver.h"
#include "glare.d3d11.VertexShader.h"
#include "glare.core.ShaderInputDeclaration.h"
#include "glare.d3d11.FormatMapping.h"

namespace Glare {

	D3D11ShaderInputDeclaration::D3D11ShaderInputDeclaration(D3D11Driver* driver) 
		: _driver(driver)
		, _d3d_input_layout(NULL)
	{

	}

	D3D11ShaderInputDeclaration::~D3D11ShaderInputDeclaration()
	{
		GLARE_SAFE_RELEASE(_d3d_input_layout, "Error while releasing D3D input layout");
	}

	void D3D11ShaderInputDeclaration::Build(Shader* shader)
	{
		D3D11ShaderInterface* d3d11_interface = static_cast<D3D11ShaderInterface*>(shader->_GetInterface());

		if (!d3d11_interface)
			return;

		GLARE_SAFE_RELEASE(_d3d_input_layout, "Error while releasing D3D input layout");

		D3D11_INPUT_ELEMENT_DESC* elements = new D3D11_INPUT_ELEMENT_DESC[InputElements.size()];

		ID3DBlob* bytecode = d3d11_interface->GetD3DByteCode();

		for (uint i = 0; i < InputElements.size(); ++i)
		{
			const ShaderInputElement& elem = InputElements[i];
			PixelFormat format = elem.Format;

			elements[i].SemanticName = elem.SemanticName.c_str();
			elements[i].SemanticIndex = elem.SemanticIndex;
			elements[i].Format = D3D11FormatMapping::MapFormat(format);
			elements[i].AlignedByteOffset = elem.Offset;
			elements[i].InputSlot = elem.InputSlot;
			elements[i].InputSlotClass = elem.InstanceElement ? D3D11_INPUT_PER_INSTANCE_DATA : D3D11_INPUT_PER_VERTEX_DATA;
			elements[i].InstanceDataStepRate = elem.InstanceFrequency;
		}

		GLARE_THROW(_driver->GetD3DDevice()->CreateInputLayout(
			elements, 
			InputElements.size(), 
			bytecode->GetBufferPointer(), 
			bytecode->GetBufferSize(), 
			&_d3d_input_layout),
			"Error while creating D3D input layout");

		delete[] elements;
	}

	ID3D11InputLayout* D3D11ShaderInputDeclaration::GetD3DInputLayout() const
	{
		return _d3d_input_layout;
	}
}
